package com.example.utils;

import com.google.gson.Gson;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.concurrent.CompletableFuture;


/**
 * @purpose http客户端
 */
public class HttpClient {

    /**
     * post 方法
     * @param url 请求路由
     * @param data 需要发送的body请求参数
     * @param headers header头
     * @return
     */
    public static Map<String, Object> post(String url, Map<String, Object> data, Map<String, String> headers) {
        //初始化返回值
        Map<String, Object> result = new HashMap<>();
        try {
            //链接远端服务器
            URL obj = new URL(url);
            HttpURLConnection con = (HttpURLConnection) obj.openConnection();

            // 设置请求方法为 POST
            con.setRequestMethod("POST");

            // 设置请求头
            if (headers != null) {
                for (Map.Entry<String, String> entry : headers.entrySet()) {
                    con.setRequestProperty(entry.getKey(), entry.getValue());
                }
            }

            // 设置允许输出
            con.setDoOutput(true);
            //需要发送的数据
            byte[] postDataBytes;
            //编码类型
            String contentType = headers != null ? headers.get("Content-Type") : null;
            //需要json编码
            if (contentType != null && contentType.contains("application/json")) {
                // 如果是 JSON 格式
                Gson gson = new Gson();
                //调用第三方库将map转json
                String jsonData = gson.toJson(data);
                //转码后，需要获取字节流，就是转化为字节，才可以被传输
                postDataBytes = jsonData.getBytes(StandardCharsets.UTF_8);
            } else {
                // 默认是 application/x-www-form-urlencoded 格式 从这里看出，java使用builder构建字符串，过于复杂了
                StringBuilder postData = new StringBuilder();
                //遍历所有的参数
                for (Map.Entry<String, Object> param : data.entrySet()) {
                    //如果不是第一个参数，则需要追加&符号
                    if (postData.length() != 0) postData.append('&');
                    //获取参数的key
                    postData.append(URLEncoder.encode(param.getKey(), "UTF-8"));
                    //拼接符号 = ,java使用的append拼接
                    postData.append('=');
                    //获取value值，转化为字符串，然后url转码，拼装
                    postData.append(URLEncoder.encode(String.valueOf(param.getValue()), "UTF-8"));
                }
                //参数集合 转 字符串
                postDataBytes = postData.toString().getBytes(StandardCharsets.UTF_8);
            }

            // 发送请求参数 获取链接的输出流，就是可写事件
            try (DataOutputStream wr = new DataOutputStream(con.getOutputStream())) {
                //发送数据
                wr.write(postDataBytes);
            }

            // 获取响应状态码
            int responseCode = con.getResponseCode();

            // 读取响应内容
            StringBuilder response = new StringBuilder();
            //获取链接的输入流，就是可读事件，读取缓冲区
            try (BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()))) {
                String inputLine;
                // 循环读取内容，直到为空结束
                while ((inputLine = in.readLine()) != null) {
                    response.append(inputLine);
                }
            }

            // 处理响应结果
            result.put("code", responseCode);
            result.put("message", "success");
            result.put("data", response.toString());
        } catch (IOException e) {
            result.put("code", 500);
            result.put("message", "请求失败: " + e.getMessage());
            result.put("data", null);
        }
        return result;
    }

    /**
     * get 方法
     * @param url 请求路由
     * @param data 需要拼接到路由上的参数
     * @return
     */
    public static Map<String, Object> get(String url, Map<String, Object> data) {
        //初始化返回值
        Map<String, Object> result = new HashMap<>();
        try {
            //构建
            StringBuilder query = new StringBuilder();
            if (data != null) {
                for (Map.Entry<String, Object> param : data.entrySet()) {
                    if (query.length() != 0) query.append('&');
                    query.append(URLEncoder.encode(param.getKey(), "UTF-8"));
                    query.append('=');
                    query.append(URLEncoder.encode(String.valueOf(param.getValue()), "UTF-8"));
                }
            }
            String fullUrl = url + (query.length() > 0 ? "?" + query.toString() : "");
            // 这个URL是一个资源管理器
            URL obj = new URL(fullUrl);
            // 这里才是返回的一个http客户端
            HttpURLConnection con = (HttpURLConnection) obj.openConnection();

            // 设置请求方法为 GET
            con.setRequestMethod("GET");

            // 获取响应状态码
            int responseCode = con.getResponseCode();

            // 读取响应内容
            StringBuilder response = new StringBuilder();
            try (BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()))) {
                String inputLine;
                while ((inputLine = in.readLine()) != null) {
                    response.append(inputLine);
                }
            }

            // 处理响应结果
            result.put("code", responseCode);
            result.put("message", "success");
            result.put("data", response.toString());
        } catch (IOException e) {
            result.put("code", 500);
            result.put("message", "请求失败: " + e.getMessage());
            result.put("data", null);
        }
        return result;
    }

    /**
     * 异步 POST 请求
     * @param url 请求路由
     * @param data 需要发送的 body 请求参数
     * @param headers header 头
     * @return CompletableFuture 包含请求结果的 Map
     */
    public static CompletableFuture<Map<String, Object>> postAsync(String url, Map<String, Object> data, Map<String, String> headers) {
        // 本项目使用多线程完成异步任务，依赖 CompletableFuture.supplyAsync(异步任务)
        return CompletableFuture.supplyAsync(() -> {
            Map<String, Object> result = new HashMap<>();
            try {
                URL obj = new URL(url);
                HttpURLConnection con = (HttpURLConnection) obj.openConnection();
                con.setRequestMethod("POST");

                if (headers != null) {
                    for (Map.Entry<String, String> entry : headers.entrySet()) {
                        con.setRequestProperty(entry.getKey(), entry.getValue());
                    }
                }

                con.setDoOutput(true);

                byte[] postDataBytes;
                String contentType = headers != null ? headers.get("Content-Type") : null;
                if (contentType != null && contentType.contains("application/json")) {
                    Gson gson = new Gson();
                    String jsonData = gson.toJson(data);
                    postDataBytes = jsonData.getBytes(StandardCharsets.UTF_8);
                } else {
                    StringBuilder postData = new StringBuilder();
                    for (Map.Entry<String, Object> param : data.entrySet()) {
                        if (postData.length() != 0) postData.append('&');
                        postData.append(URLEncoder.encode(param.getKey(), "UTF-8"));
                        postData.append('=');
                        postData.append(URLEncoder.encode(String.valueOf(param.getValue()), "UTF-8"));
                    }
                    postDataBytes = postData.toString().getBytes(StandardCharsets.UTF_8);
                }

                try (java.io.DataOutputStream wr = new java.io.DataOutputStream(con.getOutputStream())) {
                    wr.write(postDataBytes);
                }

                int responseCode = con.getResponseCode();
                StringBuilder response = new StringBuilder();
                try (BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()))) {
                    String inputLine;
                    while ((inputLine = in.readLine()) != null) {
                        response.append(inputLine);
                    }
                }

                result.put("code", responseCode);
                result.put("message", "success");
                result.put("data", response.toString());
            } catch (Exception e) {
                result.put("code", 500);
                result.put("message", "请求失败: " + e.getMessage());
                result.put("data", null);
            }
            return result;
        });
    }

    /**
     * 异步 GET 请求
     * @param url 请求路由
     * @param data 需要拼接到路由上的参数
     * @return CompletableFuture 包含请求结果的 Map
     */
    public static CompletableFuture<Map<String, Object>> getAsync(String url, Map<String, Object> data) {
        return CompletableFuture.supplyAsync(() -> {
            Map<String, Object> result = new HashMap<>();
            try {
                StringBuilder query = new StringBuilder();
                if (data != null) {
                    for (Map.Entry<String, Object> param : data.entrySet()) {
                        if (query.length() != 0) query.append('&');
                        query.append(URLEncoder.encode(param.getKey(), "UTF-8"));
                        query.append('=');
                        query.append(URLEncoder.encode(String.valueOf(param.getValue()), "UTF-8"));
                    }
                }
                String fullUrl = url + (query.length() > 0 ? "?" + query.toString() : "");

                URL obj = new URL(fullUrl);
                HttpURLConnection con = (HttpURLConnection) obj.openConnection();
                con.setRequestMethod("GET");

                int responseCode = con.getResponseCode();
                StringBuilder response = new StringBuilder();
                try (BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()))) {
                    String inputLine;
                    while ((inputLine = in.readLine()) != null) {
                        response.append(inputLine);
                    }
                }

                result.put("code", responseCode);
                result.put("message", "success");
                result.put("data", response.toString());
            } catch (Exception e) {
                result.put("code", 500);
                result.put("message", "请求失败: " + e.getMessage());
                result.put("data", null);
            }
            return result;
        });
    }

}